﻿using System;
using System.Collections.Generic;
using DavidJalbert.TinyCarControllerAdvance;
using LogSystem;
using NodeCanvas.Framework;
using RootMotion.Dynamics;
using UnityEngine;
using Yoozoo.Core.Common;
using Yoozoo.Gameplay.Liberty.Pool;
using Yoozoo.Managers.ResourceManagerV2.Runtime;
using Object = UnityEngine.Object;
using Random = UnityEngine.Random;

namespace Yoozoo.Gameplay.Liberty
{

    public class LibertyNpcManager : QualityListenerMono<LibertyNpcManager.LibertyNpcQualitySetting>
    {
        [Serializable]
        public class LibertyNpcQualitySetting : QualitySetting
        {
            public int npcTypeCount;
            public int carTypeCount;

            public int carPoolInitNum;
            public int carPoolCapacity;
            
            public int npcPoolInitNum;
            public int npcPoolCapacity;
        }

        [Serializable]
        public class NpcConfig
        {
            public int npcId;
            public int type;
            public string npcName;
            public string npcResPath;
        }

        private Dictionary<string, GameObject> npcName2Asset = new Dictionary<string, GameObject>();
        private Dictionary<int, GameObject> npcId2Asset = new Dictionary<int, GameObject>();
        
        private Dictionary<int, GameObject> uniqueId2Npc = new Dictionary<int, GameObject>();
        private Dictionary<int, int> uniqueId2NpcId = new Dictionary<int, int>();
        private Dictionary<int, GameObject> uniqueId2Car = new Dictionary<int, GameObject>();
        private Dictionary<int, int> uniqueId2CarId = new Dictionary<int, int>();

        private List<int> randomNpcIdList = new List<int>(50);
        private List<int> randomCarIdList = new List<int>(50);

        private Dictionary<int, LibertyNpcPool> _libertyNpcPoolMap = new Dictionary<int, LibertyNpcPool>(30);
        private List<LibertyNpcPool> _libertyNpcPools = new List<LibertyNpcPool>(30);

        //private ResLoader _loader;

        public bool LoadCondition(int id, int type)
        {
            // 主角不加载
            if (type == 4)
            {
                return false;
            }
            
            if (type == 1 && randomNpcIdList.Count >= CurrentQualitySetting.npcTypeCount)
            {
                return false;
            }
            
            if (type == 2 && randomCarIdList.Count >= CurrentQualitySetting.carTypeCount)
            {
                return false;
            }

            if (type == 1)
            {
                randomNpcIdList.Add(id);
                return true;
            }
            else if (type == 2)
            {
                randomCarIdList.Add(id);
                return true;
            }
            
            return false;
        }

        public void OnLoadNpc(int id, int type, string npcName,Object asset,int initNum = -1, Action<int> callback = null)
        {
            if (npcId2Asset.ContainsKey(id))
            {
                return;
            }
            
            npcName2Asset[npcName] = asset as GameObject;
            npcId2Asset[id] = asset as GameObject;
            
            // 构建npc池子
            GameObject originObject = GameObject.Instantiate(asset as GameObject);
            originObject.transform.parent = this.transform;
            originObject.SetActive(false);
            LibertyNpcPool libertyNpcPool = null;
            if (type == 2)
            {
                if (initNum == -1)
                {
                    libertyNpcPool = new LibertyNpcPool(id, CurrentQualitySetting.carPoolInitNum, CurrentQualitySetting.carPoolCapacity, originObject); // 场景中静态车辆也走对象池
                }
                else
                {
                    libertyNpcPool = new LibertyNpcPool(id, initNum, initNum * 2, originObject);
                }
            }
            else
            {
                if (initNum == -1)
                {
                    libertyNpcPool = new LibertyNpcPool(id,CurrentQualitySetting.npcPoolInitNum, CurrentQualitySetting.npcPoolCapacity, originObject);
                }
                else
                {
                    libertyNpcPool = new LibertyNpcPool(id, initNum, initNum * 2, originObject);
                }
            }
            _libertyNpcPoolMap[id] = libertyNpcPool;
            _libertyNpcPools.Add(libertyNpcPool);
            libertyNpcPool.NpcType = type;
            libertyNpcPool.PreInitASync((i =>
            {
                callback?.Invoke(i);
            }));
            
        }
        
        public void Dispose()
        {
            foreach (var u in uniqueId2Npc)
            {
                if (u.Value != null)
                {
                    GameObject.DestroyImmediate(u.Value);
                }
            }
            
            npcName2Asset.Clear();
            npcId2Asset.Clear();
            uniqueId2Npc.Clear();
            randomNpcIdList.Clear();
            uniqueId2NpcId.Clear();
            uniqueId2CarId.Clear();
            
            foreach (var npcPool in _libertyNpcPools)
            {
                npcPool.Destroy();
            }
            
            _libertyNpcPoolMap.Clear();
            _libertyNpcPools.Clear();
        }


        #region NPC

         public void AddNpc(string npcName, int uniqueId, Vector3 pos, Quaternion rot)
        {
            if (uniqueId2Npc.ContainsKey(uniqueId))
            {
                Debug.LogError(LogModule.LibertyScene,$"重复添加ID相同的NPC:{uniqueId}");
                return;
            }

            if (!npcName2Asset.ContainsKey(npcName))
            {
                Debug.LogError(LogModule.LibertyScene,$"没有此名称的NPC资源:{npcName}");
                return;
            }

            GameObject npc = GameObject.Instantiate(npcName2Asset[npcName], pos, rot, this.transform);
            npc.SetActive(true);
            uniqueId2Npc[uniqueId] = npc;
        }

        public int AddNpc(int npcId,bool random,int uniqueId, Vector3 pos, Quaternion rot)
        {

            if (uniqueId2Npc.ContainsKey(uniqueId))
            {
                Debug.LogError(LogModule.LibertyScene,$"重复添加ID相同的NPC:{uniqueId}");
                return -1;
            }

            if (random)
            {
                npcId = GetRandomNpcPool();
            }
            
            if (!npcId2Asset.ContainsKey(npcId))
            {
                Debug.LogError(LogModule.LibertyScene,$"没有此Id的NPC资源:{npcId}");
                return -1;
            }

            //GameObject npc = GameObject.Instantiate(npcId2Asset[npcId], pos, rot, this.transform);
            LibertyNpcPool npcPool = _libertyNpcPoolMap[npcId];
            GameObject npc = npcPool.GetItem();
            npc.SetActive(true);
            uniqueId2Npc[uniqueId] = npc;
            uniqueId2NpcId[uniqueId] = npcId;
            return npcId;
        }

        private List<LibertyNpcPool> _randomNpcPools = new List<LibertyNpcPool>(30); 
        private int GetRandomNpcPool()
        {
            foreach (var npcPool in _libertyNpcPools)
            {
                if (npcPool.PoolCount > 0 && npcPool.NpcType != 2 && npcPool.NpcType != 3) // 排除车辆对象池
                {
                    _randomNpcPools.Add(npcPool);
                }
            }

            if (_randomNpcPools.Count > 3)
            {
                int idx = Random.Range(0, _randomNpcPools.Count);
                return _randomNpcPools[idx].NpcId;
            }
            else
            {
                int idx = Random.Range(0, randomNpcIdList.Count);
                return randomNpcIdList[idx];
            }
        }
        

        public void RemoveNpc(int uniqueId)
        {
            if (uniqueId2NpcId.TryGetValue(uniqueId,out var npcId))
            {
                if (_libertyNpcPoolMap.TryGetValue(npcId,out var p))
                {
                    GameObject npc1;
                    if (uniqueId2Npc.TryGetValue(uniqueId, out npc1))
                    {
                        if (npc1 ==null)
                        {
                            uniqueId2Npc.Remove(uniqueId);
                            return;
                        }
                        
                        PuppetMaster puppetMaster = npc1.GetComponentInChildren<PuppetMaster>(true);
                        puppetMaster.state = PuppetMaster.State.Alive;
                        puppetMaster.mode = PuppetMaster.Mode.Disabled;
                        puppetMaster.enabled = true;
                        puppetMaster.gameObject.SetActive(true);
                        p.RecoverItem(npc1);
                        uniqueId2Npc.Remove(uniqueId);
                        return;
                    }
                }
            }
            
            GameObject npc;
            if (uniqueId2Npc.TryGetValue(uniqueId,out npc))
            {
                if (npc!=null)
                {
                    GameObject.DestroyImmediate(npc);
                    uniqueId2Npc.Remove(uniqueId);
                }
            }
        }

        public GameObject GetNpc(int uniqueId)
        {
            GameObject npc;
            if (uniqueId2Npc.TryGetValue(uniqueId, out npc))
            {
                return npc;
            }

            return null;
        }
        

        #endregion


        #region Car


        public void AddCar(string carName, int uniqueId)
        {
            if (uniqueId2Car.ContainsKey(uniqueId))
            {
                Debug.LogError(LogModule.LibertyScene,$"重复添加ID相同的车辆:{uniqueId}");
                return;
            }
            
            if (!npcName2Asset.ContainsKey(carName))
            {
                Debug.LogError(LogModule.LibertyScene,$"没有此名称的NPC资源:{carName}");
                return;
            }
            
            GameObject car = GameObject.Instantiate(npcName2Asset[carName], this.transform);
            car.SetActive(true);
            uniqueId2Car[uniqueId] = car;
        }


        private List<int> optRandomCarIdList = new List<int>(50);
        public int AddCar(int carId,bool random,int uniqueId)
        {
            if (uniqueId2Car.ContainsKey(uniqueId))
            {
                Debug.LogError(LogModule.LibertyScene,$"重复添加ID相同的车辆:{uniqueId}");
                return -1;
            }

            if (random)
            {
                optRandomCarIdList.Clear();
                foreach (var libertyNpcPool in _libertyNpcPoolMap)
                {
                    if (libertyNpcPool.Value.NpcType == 2) // 拿到车辆的对象池
                    {
                        // 优先拿到对象池中与有余量的
                        if (libertyNpcPool.Value.PoolCount> 0 && randomCarIdList.Contains(libertyNpcPool.Value.NpcId))
                        {
                            optRandomCarIdList.Add(libertyNpcPool.Value.NpcId);
                        }
                    }
                }

                if (optRandomCarIdList.Count > 0)
                {
                    int idx = Random.Range(0, optRandomCarIdList.Count);
                    carId = optRandomCarIdList[idx];
                }
                else
                {
                    int idx = Random.Range(0, randomCarIdList.Count);
                    carId = randomCarIdList[idx];
                }
            }
            
            if (!npcId2Asset.ContainsKey(carId))
            {
                Debug.LogError(LogModule.LibertyScene,$"没有此Id的车辆资源:{carId}");
                return -1;
            }

            LibertyNpcPool npcPool = _libertyNpcPoolMap[carId];
            GameObject car = npcPool.GetItem();
            car.SetActive(true);
            car.name = "Car_" + uniqueId.ToString();
            uniqueId2Car[uniqueId] = car;
            uniqueId2CarId[uniqueId] = carId;
            return carId;
        }
        

        public void RemoveCar(int uniqueId)
        {
            if (uniqueId2CarId.TryGetValue(uniqueId,out var carId))
            {
                if (_libertyNpcPoolMap.TryGetValue(carId,out var p))
                {
                    if (uniqueId2Car.TryGetValue(uniqueId,out var car1))
                    {
                        if (car1 == null)
                        {
                            uniqueId2Car.Remove(uniqueId);
                            return;
                        }

                        var go = car1.GetComponent<GraphOwner>();
                        if (go)
                        {
                            go.StopBehaviour();
                        }
                        p.RecoverItem(car1);
                        
                        uniqueId2Car.Remove(uniqueId);
                        return;
                    }
                    
                }
            }

            if (uniqueId2Car.TryGetValue(uniqueId, out var car))
            {
                if (car != null)
                {
                    GameObject.Destroy(car);
                    uniqueId2Car.Remove(uniqueId);
                }
            }
        }

        public GameObject GetCar(int uniqueId)
        {
            GameObject car;
            if (uniqueId2Car.TryGetValue(uniqueId, out car))
            {
                return car;
            }
            return null;
        }


        #endregion
        

    }
}